package src.Players;

import src.Main;
import src.NPCs.NPC;

public class PlayerAttack
{
    private int combatXPRate = 10000;
    private Player p;

    public PlayerAttack(Player _p)
    {
        p = _p;
    }

    public void attackNPC()
    {
        if(p == null)
        {
            return;
        }
        if(!canAttackNPC())
        {
            resetAttack();
            return;
        }
        boolean useBow = false;
        int wepId = p.equipment[3];
        int arrowId = p.equipment[13];
        if(wepId >= 800 && wepId <= 876 || wepId >= 4212 && wepId <= 4223 || wepId == 4734 || wepId == 6724 || wepId == 6522)
        {
            useBow = true;
        }
        NPC n = Main.m.ge.npcs[p.attackNPC];
        if(p.faceToRequest != p.attackNPC)
        {
            p.requestFaceTo(p.attackNPC);
        }
        if(useBow && Main.m.ge.getDistance(n.absX, n.absY, p.absX, p.absY) <= 8)
        {
            stopMovement();
        }
        if(p.combatDelay <= 0)
        {
            if(!useBow)
            {
                if(Main.m.ge.getDistance(n.absX, n.absY, p.absX, p.absY) != 1)
                {
                    return;
                }
                p.requestAnim(getAttackAnimation(wepId), 0);
                int hitDiff = random(getMeleePower());
                n.appendHit(hitDiff, 0);
                if(p.skillId != 3)
                {
                    p.addSkillXP((4 * combatXPRate) * hitDiff, p.skillId);
                    p.addSkillXP((2 * combatXPRate) * hitDiff, 3);
                }
                else
                {
                    p.addSkillXP((2 * combatXPRate) * hitDiff, 0);
                    p.addSkillXP((2 * combatXPRate) * hitDiff, 1);
                    p.addSkillXP((2 * combatXPRate) * hitDiff, 2);
                    p.addSkillXP((2 * combatXPRate) * hitDiff, 3);
                }
                n.randomWalk = false;
                n.killingPlayerId = p.playerIndex;
                n.isUnderPlayerAttack = true;
                p.combatDelay = getWeaponSpeed(wepId);
            }
            else if(useBow)
            {
                if(Main.m.ge.getDistance(n.absX, n.absY, p.absX, p.absY) > 8)
                {
                    return;
                }
                p.requestAnim(getAttackAnimation(wepId), 0);
                int hitDiff = random(getRangedPower(wepId, arrowId));
                n.appendHit(hitDiff, 0);
                if(p.skillId != 3)
                {
                    p.addSkillXP((2 * combatXPRate) * hitDiff, 3);
                    p.addSkillXP((4 * combatXPRate) * hitDiff, 4);
                }
                else
                {
                    p.addSkillXP((2 * combatXPRate) * hitDiff, 1);
                    p.addSkillXP((2 * combatXPRate) * hitDiff, 3);
                    p.addSkillXP((2 * combatXPRate) * hitDiff, 4);
                }
                n.randomWalk = false;
                n.killingPlayerId = p.playerIndex;
                n.isUnderPlayerAttack = true;
                p.combatDelay = getWeaponSpeed(wepId);
            }
        }
    }

    public void attackPlayer()
    {
        if(p == null)
        {
            return;
        }
        if(!canAttackPlayer())
        {
            resetAttack();
            return;
        }
        boolean useBow = false;
        int wepId = p.equipment[3];
        int arrowId = p.equipment[13];
        if(wepId >= 800 && wepId <= 876 || wepId >= 4212 && wepId <= 4223 || wepId == 4734 || wepId == 6724 || wepId == 6522)
        {
            useBow = true;
        }
	System.out.println(p.attackPlayer);
        Player plr = Main.m.ge.players[p.attackPlayer];
	System.out.println(plr);
	System.out.println(p.playerIndex+" : "+plr.playerIndex);
        if(p.faceToRequest != (p.attackPlayer + 32768))
        {
            p.requestFaceTo(p.attackPlayer + 32768);
        }
        if(useBow && Main.m.ge.getDistance(plr.absX, plr.absY, p.absX, p.absY) <= 8)
        {
            stopMovement();
        }
        if(p.combatDelay <= 0)
        {
            if(!useBow)
            {
                if(Main.m.ge.getDistance(plr.absX, plr.absY, p.absX, p.absY) != 1)
                {
                    return;
                }
                int meleeAtk = random(getMeleeAtk(p));
                int meleeDef = random(getMeleeDef(plr));
                p.requestAnim(getAttackAnimation(wepId), 0);
                int hitDiff = random(getMeleePower());
                if(meleeAtk < meleeDef)
                {
                    hitDiff = 0;
                }
                plr.killedBy[p.playerIndex] += hitDiff;
                plr.appendHit(hitDiff, 0);
                if(p.skillId != 3)
                {
                    p.addSkillXP((4 * combatXPRate) * hitDiff, p.skillId);
                    p.addSkillXP((2 * combatXPRate) * hitDiff, 3);
                }
                else
                {
                    p.addSkillXP((2 * combatXPRate) * hitDiff, 0);
                    p.addSkillXP((2 * combatXPRate) * hitDiff, 1);
                    p.addSkillXP((2 * combatXPRate) * hitDiff, 2);
                    p.addSkillXP((2 * combatXPRate) * hitDiff, 3);
                }
                p.combatDelay = getWeaponSpeed(wepId);
            }
            else if(useBow)
            {
                if(Main.m.ge.getDistance(plr.absX, plr.absY, p.absX, p.absY) > 8)
                {
                    return;
                }
                int rangedAtk = random(getRangedAtk(p));
                int rangedDef = random(getRangedDef(plr));
                p.requestAnim(getAttackAnimation(wepId), 0);
                int hitDiff = random(getRangedPower(wepId, arrowId));
                if(rangedAtk < rangedDef)
                {
                    hitDiff = 0;
                }
                plr.killedBy[p.playerIndex] += hitDiff;
                plr.appendHit(hitDiff, 0);
                if(p.skillId != 3)
                {
                    p.addSkillXP((2 * combatXPRate) * hitDiff, 3);
                    p.addSkillXP((4 * combatXPRate) * hitDiff, 4);
                }
                else
                {
                    p.addSkillXP((2 * combatXPRate) * hitDiff, 1);
                    p.addSkillXP((2 * combatXPRate) * hitDiff, 3);
                    p.addSkillXP((2 * combatXPRate) * hitDiff, 4);
                }
                p.combatDelay = getWeaponSpeed(wepId);
            }
        }
    }

    public int getMeleePower()
    {
        if(p == null)
        {
            return 1;
        }
        double maxHit = 1.06 + (p.equipmentBonus[10] * p.skillLvl[2]) * 0.00178;
        if(fullDharokEquipped())
        {
            maxHit += (p.getLevelForXP(3) - p.skillLvl[3]) / 2;
        }
        return (int)(maxHit += p.skillLvl[2] * 0.16);
    }

    public int getRangedPower(int wepId, int arrowId)
    {
        if(p == null)
        {
            return 1;
        }
        double maxHit = 0;
	maxHit += 1.06 + (p.skillLvl[4] * 0.00128);
	maxHit += p.skillLvl[4] * 0.16;
	if(arrowId == 882 || arrowId == 883)
        {
            maxHit *= 1.042;
        }
	else if(arrowId == 884 || arrowId == 885)
        {
            maxHit *= 1.044;
        }
	else if(arrowId == 886 || arrowId == 887)
        {
            maxHit *= 1.134;
        }
	else if(arrowId == 888 || arrowId == 889)
        {
            maxHit *= 1.2;
        }
	else if(arrowId == 890 || arrowId == 891)
        {
            maxHit *= 1.35;
        }
	else if(arrowId == 892 || arrowId == 893)
        {
            maxHit *= 1.65;
        }
	else
        {
            maxHit *= 1.04;
        }
        return (int)Math.floor(maxHit);
    }

    public boolean canAttackNPC()
    {
        if(p == null || p.isDead)
        {
            return false;
        }
        else if(p.attackNPC < 1 || p.attackNPC >= Main.m.ge.maxNPCs || Main.m.ge.npcs[p.attackNPC] == null)
        {
            return false;
        }
        NPC n = Main.m.ge.npcs[p.attackNPC];
        if(n.maxHP <= 0)
        {
            p.frame.sendMessage(p, "You cannot attack non-combat NPCs.");
            return false;
        }
        else if(n.isDead || n.currentHP <= 0)
        {
            //p.frame.sendMessage(p, "This NPC is already dead.");
            return false;
        }
        return true;
    }

    public boolean canAttackPlayer()
    {
        if(p == null || p.isDead)
        {
            return false;
        }
        else if(p.attackPlayer < 1 || p.attackPlayer >= Main.m.ge.maxPlayers || Main.m.ge.players[p.attackPlayer] == null)
        {
            return false;
        }
        if(!Main.m.ge.wildernessArea(p.absX, p.absY))
        {
            p.frame.sendMessage(p, "You are not in the wild.");
            return false;
        }
        Player plr = Main.m.ge.players[p.attackPlayer];
        if(plr.isDead || plr.skillLvl[3] <= 0)
        {
            //p.frame.sendMessage(p, "This NPC is already dead.");
            return false;
        }
        if(!Main.m.ge.wildernessArea(plr.absX, plr.absY))
        {
            p.frame.sendMessage(p, "This player is not in the wild.");
            return false;
        }
        return true;
    }

    public void resetAttack()
    {
        if(p == null)
        {
            return;
        }
        p.attackingNPC = false;
        p.attackingPlayer = false;
        p.attackNPC = 0;
        p.attackPlayer = 0;
    }

    public void stopMovement()
    {
        if(p == null)
        {
            return;
        }
        if(p.teleportToX == -1 && p.teleportToY == -1)
        {
            //p.teleportToX = p.absX;
            //p.teleportToY = p.absY;
        }
        p.newWalkCmdSteps = 0;
        p.newWalkCmdX[0] = p.newWalkCmdY[0] = 0;
        if(p.canWalkDelay <= 0)
        {
            p.canWalkDelay = 2;
        }
        //Main.m.ge.moveP.getNextPlayerMovement(p); //As nice as this is, can screw your coordsup on other peoples screens so avoid it.
    }

    private int random(int range)
    {
        return (int)(Math.random() * (range + 1));
    }

    public int getWeaponSpeed(int wepId)
    {
        String weapon = Main.m.ge.item.getItemName(wepId);
        if(weapon.endsWith("Granite maul"))
        {
            return 7;
        }
        else if(weapon.endsWith("Toktz-xil-ak"))
        {
            return 4;
        }
        else if(weapon.endsWith("Tzhaar-ket-em"))
        {
            return 5;
        }
        else if(weapon.endsWith("Tzhaar-ket-om"))
        {
            return 7;
        }
        else if(weapon.endsWith("Toktz-xil-ek"))
        {
            return 4;
        }
        else if(weapon.equals("Abyssal whip"))
        {
            return 4;
        }
        else if(weapon.equals("Dharoks greataxe"))
        {
            return 7;
        }
        else if(weapon.equals("Torags hammers"))
        {
            return 5;
        }
        else if(weapon.equals("Guthans warspear"))
        {
            return 5;
        }
        else if(weapon.equals("Veracs flail"))
        {
            return 5;
        }
        else if(weapon.equals("Zamorak staff"))
        {
            return 4;
        }
        else if(weapon.equals("Saradomin staff"))
        {
            return 4;
        }
        else if(weapon.equals("Guthix staff"))
        {
            return 4;
        }
        else if(weapon.equals("Slayer's staff"))
        {
            return 4;
        }
        else if(weapon.equals("Toktz-mej-tal"))
        {
            return 6;
        }
        else if(weapon.equals("Ahrims staff"))
        {
            return 6;
        }
        else if(weapon.equals("Ancient staff"))
        {
            return 4;
        }
        else if(weapon.equals("Ogre bow"))
        {
            return 8;
        }
        else if(weapon.equals("Comp ogre bow"))
        {
            return 5;
        }
        else if(weapon.equals("Seercull"))
        {
            return 5;
        }
        else if(weapon.equals("Karils crossbow"))
        {
            return 4;
        }
        else if(weapon.equals("Toktz-xil-ul"))
        {
            return 4;
        }
        else if(weapon.startsWith("Crystal bow"))
        {
            return 5;
        }
        else if(weapon.startsWith("New crystal bow"))
        {
            return 5;
        }
        else if(weapon.endsWith("dagger"))
        {
            return 4;
        }
        else if(weapon.endsWith(" sword"))
        {
            return 4;
        }
        else if(weapon.endsWith("longsword"))
        {
            return 5;
        }
        else if(weapon.endsWith("scimitar"))
        {
            return 4;
        }
        else if(weapon.endsWith("mace"))
        {
            return 5;
        }
        else if(weapon.endsWith(" axe"))
        {
            return 5;
        }
        else if(weapon.endsWith("battleaxe"))
        {
            return 6;
        }
        else if(weapon.endsWith("warhammer"))
        {
            return 6;
        }
        else if(weapon.endsWith("2h sword"))
        {
            return 7;
        }
        else if(weapon.endsWith(" spear"))
        {
            return 5;
        }
        else if(weapon.endsWith(" claws"))
        {
            return 4;
        }
        else if(weapon.endsWith("halberd"))
        {
            return 7;
        }
        else if(weapon.endsWith("pickaxe"))
        {
            return 5;
        }
        else if(weapon.endsWith(" staff"))
        {
            return 5;
        }
        else if(weapon.endsWith(" battlestaff"))
        {
            return 5;
        }
        else if(weapon.endsWith("longbow"))
        {
            return 6;
        }
        else if(weapon.endsWith("shortbow"))
        {
            return 4;
        }
        else if(weapon.endsWith(" dart"))
        {
            return 3;
        }
        else if(weapon.endsWith(" knife"))
        {
            return 3;
        }
        else if(weapon.endsWith("thrownaxe"))
        {
            return 5;
        }
        else if(weapon.endsWith("javelin"))
        {
            return 6;
        }
        else
        {
            return 6;
        }
    }

    public int getAttackAnimation(int wepId)
    {
        String weapon = Main.m.ge.item.getItemName(wepId);
        if(weapon.equals("Unarmed"))
        {
            return 422;
        }
        else if(weapon.equals("Guthans warspear"))
        {
            return 2081;
        }
        else if(weapon.startsWith("Dragon dagger"))
        {
            return 402;
        }
        else if(weapon.equals("Dharoks greataxe"))
        {
            return 2066;
        }
        else if(weapon.equals("Karils crossbow"))
        {
            return 2075;
        }
        else if(weapon.equals("Tzhaar-ket-om"))
        {
            return 2661;
        }
        else if(weapon.equals("Granite maul"))
        {
            return 1665;
        }
        else if(weapon.equals("Veracs flail"))
        {
            return 2062;
        }
        else if(weapon.equals("Abyssal whip"))
        {
            return 1658;
        }
        else if(weapon.equals("Torags hammers"))
        {
            return 2068;
        }
        else if(weapon.equals("Toktz-xil-ul"))
        {
            return 2614;
        }
        else if(weapon.endsWith("shortbow") || weapon.equals("Shortbow") || weapon.endsWith("longbow") || 
        weapon.equals("Longbow") || weapon.equals("Seercull"))
        {
            return 426;
        }
        else if(weapon.endsWith("thrownaxe") || weapon.endsWith("dart") || weapon.endsWith("javelin") || 
        weapon.endsWith("knife"))
        {
            return 0x326;
        }
        else if(weapon.endsWith("crossbow") || weapon.equals("Crossbow"))
        {
            return 427;
        }
        else if(weapon.endsWith("dagger") || weapon.endsWith("pickaxe"))
        {
            return 412;
        }
        else if(weapon.endsWith("2h sword"))
        {
            return 407;
        }
        else if(weapon.endsWith("sword") || weapon.endsWith("mace") || weapon.endsWith("longsword") || 
        weapon.endsWith("scimitar"))
        {
            return 451;
        }
        else if(weapon.endsWith("axe") || weapon.endsWith("battleaxe"))
        {
            return 1833;
        }
        else if(weapon.endsWith("halberd") || weapon.endsWith("spear"))
        {
            return 440;
        }
        return 451;
    }

    public int getMeleeDef(Player p)
    {
        if(p == null)
        {
            return 0;
        }
        return (p.skillLvl[1] + p.equipmentBonus[bestMeleeDef(p)]);
    }

    public int getRangedDef(Player p)
    {
        if(p == null)
        {
            return 0;
        }
        return (p.skillLvl[1] + p.equipmentBonus[9]);
    }

    public int getMeleeAtk(Player p)
    {
        if(p == null)
        {
            return 0;
        }
        return (p.skillLvl[0] + p.equipmentBonus[bestMeleeAtk(p)] + p.equipmentBonus[bestMeleeAtk(p)]);
    }

    public int getRangedAtk(Player p)
    {
        if(p == null)
        {
            return 0;
        }
        return (p.skillLvl[4] + p.equipmentBonus[4] + p.equipmentBonus[4]);
    }

    public int bestMeleeDef(Player p)
    {
        if(p == null)
            return 5;
        if (p.equipmentBonus[5] > p.equipmentBonus[6] && p.equipmentBonus[5] > p.equipmentBonus[7])
            return 5;
        if (p.equipmentBonus[6] > p.equipmentBonus[5] && p.equipmentBonus[6] > p.equipmentBonus[7])
            return 6;
        if (p.equipmentBonus[7] > p.equipmentBonus[5] && p.equipmentBonus[7] > p.equipmentBonus[6])
            return 7;
        return 5;
    }

    public int bestMeleeAtk(Player p)
    {
        if(p == null)
            return 0;
        if (p.equipmentBonus[0] > p.equipmentBonus[1] && p.equipmentBonus[0] > p.equipmentBonus[2])
            return 0;
        if (p.equipmentBonus[1] > p.equipmentBonus[0] && p.equipmentBonus[1] > p.equipmentBonus[2])
            return 1;
        if (p.equipmentBonus[2] > p.equipmentBonus[1] && p.equipmentBonus[2] > p.equipmentBonus[0])
            return 2;
        return 0;
    }

    public boolean fullDharokEquipped()
    {
        if(p == null)
        {
            return false;
        }
        return (p.equipment[0] == 4716 && p.equipment[4] == 4720 && p.equipment[7] == 4722 && p.equipment[3] == 4718);
    }
}